文章目录

标签:JavaScript 设计模式


前言:最近在学习Node.js,了解了node中的事件驱动机制,而相应的事件循环实现和设计模式中观察者相似,于是打算将观察者模式顺带学习一番。

定义
通过查阅书籍,以及一些其他文档,观察者模式的定义可以简述为以下几个步骤:

  1. 目标状态发生观察者感兴趣的改变
  2. 目标对象发送一个通知消息(怎样发送,或是通过什么发送呢)
  3. 目标对象调用每个观察者的更新方法
  4. 最后,当观察者不再对目标状态的更新感兴趣,则观察者将自动分离

角色及作用

  • Subject (目标) 维护一系列观察者,方便添加或者删除观察者;
  • Observer(观察者)为那些目标状态发生改变时需获得通知的对象(具体观察者?)提供一个更新接口;
  • ConcreteSubject(具体目标) 状态发生改变时,向Observer发出通知,存储ConcreteObserver的状态;
  • ConcreteObserver(具体观察者)存储一个ConcreteObserver的引用,实现更新接口,以使自身状态和目标状态保持一致。

以下实现一个观察者模式的组件

首先,模拟一个目标可能拥有的一系列Observer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
function ObserverList() {
this.observerlist = [];
}
ObserverList.prototype.Add = function (obj) {
this.observerlist.push(obj);
};
ObserverList.prototype.Empty = function () {
this.observerlist.length = 0;
// this.observerlist = [];
};
ObserverList.prototype.Count = function () {
return this.observerlist.length;
};
ObserverList.prototype.Get = function (index) {
if (index > -1 && index < this.observerlist.length) {
return this.observerlist[index];
}
};
// 从观察者头尾添加其他观察者
ObserverList.prototype.Insert = function (obj, index) {
let pointer = -1;
if (index === 0) {
this.observerlist.unshift(obj);
pointer = index;
} else if (index === this.observerlist.length) {
this.observerlist.push(obj);
pointer = index;
}
return pointer;
};
ObserverList.prototype.IndexOf = function (obj, startIndex) {
let pointer = -1, i = startIndex;
while(i < this.observerlist.length) {
if (this.observerlist[i] === obj) {
pointer = i;
}
i++;
}
return pointer;
};
// 从列表首尾删除观察者
ObserverList.prototype.RemoveIndexAt = function (index) {
if (index === 0) {
this.observerlist.shift();
} else if (index === this.observerlist.length - 1) {
this.observerlist.pop();
}
};
function extend(obj, extention) {
for (let key in obj) {
extention[key] = obj[key];
}
};

接下来,来模拟目标(Subject)和在观察者列表上添加。删除或通知观察者的能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Subject(){
this.observers = new ObserverList();
}
Subject.prototype.AddObserver = function (observer) {
this.observers.Add(observer);
};
Subject.prototype.RemoveObserver = function (observer) {
this.observers.RemoveIndexAt(this.observers.IndexOf(observer, 0));
};
Subject.prototype.Notify = function (context) {
let observerCount = this.observers.Count();
for (let i = 0; i < observerCount; i++) {
// 这里的Update方法将在Observer实例中实现,一般会重写自定义更新行为;
this.observers.Get(i).Update(context);
}
};

然后定义一个框架来创建新的Observer

1
2
3
4
5
6
7
//模拟一个观察者对象
function Observer() {
//之后的实例中会重写自定义的Update方法
this.Update = () => {
//...
}
}

上面实现了一个观察者模式,接下来通过一个实例程序,学习怎样使用观察者模式:

  1. 用于向页面添加新可见的CheckBox按钮;
  2. 控制CheckBox,将充当一个目标,通知其他CheckBox需要进行检查;
  3. 用于添加新CheckBox的容器

实现代码如下:

1
2
3
<button id="addNewObserver">Add New Observer checkbox</button>
<input type="checkbox" id="mainCheckbox">
<div id="observerContainer"></div>

下面是样例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 样例脚本
var controlCheckbox = document.getElementById('mainCheckbox'),
addBtn = document.getElementById('addNewObserver'),
container = document.getElementById('observerContainer');
// 目标对象,用于控制所有的观察者 具体目标ConcreteSubject
extend(new Subject(), controlCheckbox);
// 点击CheckBox会触发通知到观察者上
controlCheckbox["onclick"] = new Function("controlCheckbox.Notify(controlCheckbox.checked)");
// 添加新的观察者
addBtn["onclick"] = AddNewObserver;
// 具体观察者ConcreteObserver
function AddNewObserver() {
var check = document.createElement("input");
check.type = "checkbox";
extend(new Observer(), check);
check.Update = function (value) {
this.checked = value;
};
controlCheckbox.AddObserver(check);
container.appendChild(check);
}

以上就是观察者模式的简单实现和使用,主要弄清楚目标,观察者,具体目标,具体观察者这四者之间的关系,以及弄清它们之间的调用的关系。总体说来还是比较容易理解。

主要参考:JavaScript设计模式 [美] Addy Osnabi 著

文章目录